package 剑指Offer_day09;

/**
 * 剑指 Offer 47. 礼物的最大价值
 *
 * 在一个 m*n 的棋盘的每一格都放有一个礼物，每个礼物都有一定的价值（价值大于 0）。你可以从棋盘的左上角开始拿格子里的礼物，并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值，请计算你最多能拿到多少价值的礼物？
 *
 *
 *
 * 示例 1:
 *
 * 输入:
 * [
 *  [1,3,1],
 *  [1,5,1],
 *  [4,2,1]
 * ]
 * 输出: 12
 * 解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
 *
 *
 * 提示：
 *
 * 0 < grid.length <= 200
 * 0 < grid[0].length <= 200
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class Offer_47 {

    public int maxValue(int[][] grid) {


        /**
         * 动态规划  走到当前位置的最大值 =  max(走到上方的最大值,走到左边的最大值) + 当前位置的值
         * 状态转移方程 dp[i][j] = max(dp[i][j-1],dp[i-1][j])+ grid[i][j]
         */

        int i = grid.length;
        int j = grid[0].length;

        //定义一个 状态数组 保存走到当前格子 的最大礼物价值
        int[][] dp = new int[i][j];

        //由于 只能向右 和向下 所以状态数组第一行 和第一列  可以直接算出来


        dp[0][0] = grid[0][0];
        //计算dp 第一行的值
        for (int i1 = 1; i1 < grid[0].length; i1++) {
            dp[0][i1] = dp[0][i1-1]+grid[0][i1];
        }
        //计算dp 第一列的值
        for (int k = 1; k <dp.length ; k++) {
            dp[k][0] = dp[k-1][0]+grid[k][0];
        }

        //遍历出 状态数组
        for (int k = 1; k < grid.length; k++) {
            for (int l = 1; l < grid[0].length; l++) {

                dp[k][l] = Math.max(dp[k][l-1],dp[k-1][l])+grid[k][l];

            }
        }


        return dp[i-1][j-1];


    }

    public static void main(String[] args) {

        Offer_47 offer_47 = new Offer_47();

        int i = offer_47.maxValue(new int[][]{{1, 3, 1}, {1, 5, 1}, {4, 2, 1}});


    }

}
